﻿using DEL;
using IDAL;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;

//提供对数据库的一些基本操作，提供给业务逻辑层，由业务层组装出一些强大的操作
//基类中包含有创建人、创建时间、修改人、修改时间，这些是自动生成的逻辑
namespace DAL
{
    /// <summary>
    /// 仓储基类，abstract表示不可以实例化
    /// DAL项目是对IDAL项目接口的实现，项目中要创建DbContext类，对于DbContext类很多人讨论过它对数据库存取的效率，
    /// MSDN中说其是轻量的， 创建不需要很大开销，它也不是线程安全的对象，并且具有数据容器的性质（跟踪），
    /// 因此很多人认为不应该将其静态化、单例化。但是对用户的单次请求来说实现DbContext唯一是合理的。
    /// </summary>
    /// <typeparam name="TEntity">实体类型</typeparam>    
    public abstract class BaseRepository<TEntity> : IBaseRepository<TEntity> where TEntity : BaseT, new()    //new()表示T必须可以实例化
    {
        //定义数据访问上下文对象
        protected readonly DbContext _context;
        private DbSet<TEntity> _entities;

        #region 构造函数
        public BaseRepository()
        {
            this._context = new EFDbContext();
        }
        #endregion

        #region 属性
        protected virtual DbSet<TEntity> Entities
        {
            get
            {
                if (_entities == null)
                {
                    _entities = _context.Set<TEntity>();
                }
                return _entities;
            }
        }

        public virtual IQueryable<TEntity> Table
        {
            get
            {
                return this.Entities;
            }
        }
        #endregion

        #region 新增实体       

        /// <summary>
        /// 新增实体，返回对应的实体对象
        /// </summary>
        /// <param name="entity"></param>
        public virtual int AddEntity(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            entity.CreatedOn = DateTime.Now;    //添加时，实体CreatedOn字段自动生成
            entity.UpdatedOn = DateTime.Now;
            _context.Add(entity);
            return _context.SaveChanges();  //因为可能要返回自动增长的ID，所以把整个实体返回，否则可以直接返回bool
        }

        public virtual async Task<int> AddEntityAsync(TEntity entity)    //virtual方法说明继承类可以对此方法进行覆盖
        {
            entity.CreatedOn = DateTime.Now;    //添加时，实体CreatedOn字段自动生成
            entity.UpdatedOn = DateTime.Now;
            _context.Entry(entity).State = EntityState.Added;
            return await _context.SaveChangesAsync();
        }

        #endregion

        #region 修改实体
        /// <summary>
        /// 修改一条数据，会修改所有列的值，没有赋值的属性将会被赋予属性类型的默认值
        /// </summary>
        /// <param name="entity"></param>
        /// <returns>返回所影响的行</returns>
        public virtual int ModifyEntity(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            entity.UpdatedOn = DateTime.Now;    //修改时实体UpdatedOn字段自动更新
            _context.Update(entity);            
            return _context.SaveChanges();
        }

        public async virtual Task<int> ModifyEntityAsync(TEntity entity)
        {
            entity.UpdatedOn = DateTime.Now;    //修改时实体UpdatedOn字段自动更新
            _context.Set<TEntity>().Attach(entity);   //将对象附加到EF 容器                
            _context.Entry<TEntity>(entity).State = EntityState.Modified;
            return await _context.SaveChangesAsync();
        }
        #endregion

        #region 删除实体
        /// <summary>
        /// 删除一个实体对象
        /// </summary>
        /// <param name="entity">必须包含要删除id的对象</param>
        /// <returns></returns>
        public virtual bool DeleteEntity(TEntity entity)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");

            _context.Remove(entity);
            return _context.SaveChanges() > 0;

        }

        public async virtual Task<bool> DeleteEntityAsync(TEntity entity)
        {            
            _context.Set<TEntity>().Attach(entity);
            _context.Entry<TEntity>(entity).State = EntityState.Deleted;
            return await _context.SaveChangesAsync() > 0;
        }

        /// <summary>
        /// 根据条件批量删除实体对象
        /// </summary>
        /// <param name="whereLambds"></param>
        /// <returns></returns>
        public virtual bool DeleteEntitysByLambda(Expression<Func<TEntity, bool>> whereLambda)
        {
            var data = _context.Set<TEntity>().Where<TEntity>(whereLambda).ToList();
            foreach (var item in data)
            {
                _context.Set<TEntity>().Attach(item); //先附加到EF 容器
                _context.Entry<TEntity>(item).State = EntityState.Deleted;    //标识为删除状态
            }
            return _context.SaveChanges() > 0;    //一次性生成sql语句 到数据库执行删除
        }

        public async virtual Task<bool> DeleteEntitysByLambdaAsync(Expression<Func<TEntity, bool>> whereLambda)
        {
            using (var _context = new EFDbContext())
            {
                var data = _context.Set<TEntity>().Where<TEntity>(whereLambda).ToList();
                foreach (var item in data)
                {
                    _context.Set<TEntity>().Attach(item); //先附加到EF 容器
                    _context.Entry<TEntity>(item).State = EntityState.Deleted;    //标识为删除状态
                }
                return await _context.SaveChangesAsync() > 0;    //一次性生成sql语句 到数据库执行删除    
            }
        }
        #endregion

        #region 查找实体 IQueryable只存贮数据库操作语句，不立即运行，从而可以实现后继修改数据库操作语句  
        /// <summary>
        /// 根据Id查找实体
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public virtual TEntity GetEntityById(int id)
        {
            return Table.SingleOrDefault(t => t.Id == id);
        }
        public virtual async Task<TEntity> GetEntityByIdAsync(int id)
        {
            return await Table.SingleOrDefaultAsync(t => t.Id == id);
        }
               
        public IQueryable<TEntity> GetEntitysByLambdaAndSort(Expression<Func<TEntity, bool>> whereLambda, Expression<Func<TEntity, object>> orderLambda, bool isAsc)
        {
                var query = Table.Where(whereLambda).Where(o => !o.IsDeleted);
                if (isAsc)
                    query = query.OrderBy(orderLambda);
                else
                    query = query.OrderByDescending(orderLambda);
                return query;           
        }
        
        public IQueryable<TEntity> GetPagedEntitysByLambdaAndSort(int pageIndex, int pageSize, out int rowCount, out int pageCount, Expression<Func<TEntity, bool>> whereLambda, Expression<Func<TEntity, object>> orderLambda, bool isAsc)
        {
                var query = Table.Where(whereLambda).Where(o => !o.IsDeleted);
                rowCount = query.Count();   //得到总的条数
                if (rowCount % pageSize == 0)
                {
                    pageCount = rowCount / pageSize;
                }
                else
                {
                    pageCount = rowCount / pageSize + 1;
                }

                if (isAsc)
                    query = query.OrderBy(orderLambda);
                else
                    query = query.OrderByDescending(orderLambda);

                return query.Skip((pageIndex - 1) * pageSize).Take(pageSize);
           
        }

        #endregion

        public int Count(Expression<Func<TEntity, bool>> whereLambda)
        {
            return Table.Count(whereLambda);
            
        }

        public bool Exist(Expression<Func<TEntity, bool>> whereLambda)
        {            
            return Table.Any(whereLambda);            
        }
    }

}
